package cn.jaye.fabric.domain.service;

import cn.jaye.fabric.common.constants.mapping.Table;
import cn.jaye.fabric.domain.model.MOrderer;
import cn.jaye.fabric.domain.model.MPeer;
import cn.jaye.fabric.domain.model.Org;
import cn.jaye.fabric.domain.repository.PeerRepository;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.hyperledger.fabric.sdk.EventHub;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.Orderer;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author Jaye
 * @create 2018-05-15 11:26
 */
@Service
public class PeerService {

    @Autowired
    private PeerRepository peerRepository;

    @Autowired
    private HFClient hfClient;

    @Autowired
    private ConfigService configService;

    @Autowired
    private OrgService orgService;

    public List<MPeer> getMPeerByOrgId(String orgId) {
        return peerRepository.selectList(new EntityWrapper<MPeer>().eq(Table.Peer.orgId.getFieldValue(), orgId));
    }

    public List<MPeer> getMPeerByPeerId(String[] names) {
        return null;
    }

    public Set<Peer> getPeers(String orgId, String domainName) throws InvalidArgumentException {
        Set<Peer> peerLinkedList = new HashSet<>();
        List<MPeer> mPeers = getMPeerByOrgId(orgId);
        for (MPeer mpeer : mPeers) {
            peerLinkedList.add(hfClient.newPeer(mpeer.getPeerName(),
                    getPeerLocation(mpeer), configService.getPeerProperties(mpeer.getPeerName(), domainName, orgService.getOrg(orgId).getOrgName())));
        }
        return peerLinkedList;
    }

    public Set<Peer> getPeersByPeerIds(Org org, String[] peerIds) throws InvalidArgumentException {
        Set<Peer> peerLinkedList = new HashSet<>();
        List<MPeer> mPeers = getMPeerByOrgId(org.getOrgId());
        for (MPeer mpeer : mPeers) {
            for (String peerId : peerIds) {
                if (mpeer.getPeerId().equals(peerId)) {
                    peerLinkedList.add(hfClient.newPeer(mpeer.getPeerName(),
                            getPeerLocation(mpeer), configService.getPeerProperties(mpeer.getPeerName(), org.getDomainName(), org.getOrgName())));
                }
            }
        }
        return peerLinkedList;
    }

    public Set<Peer> getPeers(Org org) throws InvalidArgumentException {
        Set<Peer> peerLinkedList = new HashSet<>();
        List<MPeer> mPeers = getMPeerByOrgId(org.getOrgId());
        for (MPeer mpeer : mPeers) {
            peerLinkedList.add(hfClient.newPeer(mpeer.getPeerName(),
                    getPeerLocation(mpeer), configService.getPeerProperties(mpeer.getPeerName(), org.getDomainName(), org.getOrgName())));
        }
        return peerLinkedList;
    }

    public Peer getPeer(String peerId) throws InvalidArgumentException {
        MPeer mPeer = peerRepository.selectOne(new EntityWrapper<MPeer>().eq(Table.Peer.peerId.getFieldValue(), peerId));
        return convert(mPeer);
    }

    private Peer convert(MPeer mPeer) throws InvalidArgumentException {
        return hfClient.newPeer(mPeer.getPeerName(), getPeerLocation(mPeer));
    }

    private EventHub convertEventHub(MPeer mPeer) throws InvalidArgumentException {
        return hfClient.newEventHub(mPeer.getPeerName(), getPeerLocation(mPeer));
    }

    public Set<Peer> getPeers(String channelName) throws InvalidArgumentException {
        Set<Peer> peerLinkedList = new HashSet<>();
        List<MPeer> mPeers = peerRepository.selectPeerByChannel(channelName);
        for (MPeer mpeer : mPeers) {
            peerLinkedList.add(hfClient.newPeer(mpeer.getPeerName(),
                    getPeerLocation(mpeer)));
        }
        return peerLinkedList;
    }
//    public

    //    public void create() {
//        return;
//    }
//    public Set<Peer> getPeersByPeerNames(Org org, String[] mPeers) throws InvalidArgumentException {
//        Set<Peer> peerLinkedList = new HashSet<>();
//        List<MPeer> mPeers = getMPeerByOrgId(org.getOrgId());
//        for (MPeer mpeer : mPeers) {
//            for (String peerName : peerNames) {
//                if (mpeer.getPeerName().equals(peerName)) {
//                    peerLinkedList.add(hfClient.newPeer(mpeer.getPeerName(),
//                            getPeerLocation(mpeer), configService.getPeerProperties(mpeer.getPeerName(), org.getDomainName())));
//                }
//            }
//        }
//        return peerLinkedList;
//    }
    public LinkedList<EventHub> getEventHubsByPeerIds(Org org, String[] peerIds) throws InvalidArgumentException {
        LinkedList<EventHub> eventHubLinkedList = new LinkedList<>();
        List<MPeer> mPeers = getMPeerByOrgId(org.getOrgId());
        for (MPeer mpeer : mPeers) {
            for (String peerId : peerIds) {
                if (mpeer.getPeerId().equals(peerId)) {
                    eventHubLinkedList.add(hfClient.newEventHub(mpeer.getPeerName(),
                            getEventHubLocation(mpeer), configService.getEventHubProperties(mpeer.getPeerName(), org.getDomainName(), org.getOrgName())));
                }
            }
        }
        return eventHubLinkedList;
    }

    public LinkedList<EventHub> getEventHubs(Org org) throws InvalidArgumentException {
        LinkedList<EventHub> eventHubLinkedList = new LinkedList<>();
        List<MPeer> mPeers = getMPeerByOrgId(org.getOrgId());
        for (MPeer mpeer : mPeers) {
            eventHubLinkedList.add(hfClient.newEventHub(mpeer.getPeerName(),
                    getEventHubLocation(mpeer), configService.getEventHubProperties(mpeer.getPeerName(), org.getDomainName(), org.getOrgName())));
        }
        return eventHubLinkedList;
    }

    public LinkedList<EventHub> getEventHubsByChannel(String channelName) throws InvalidArgumentException {
        List<MPeer> mPeers = peerRepository.selectPeerByChannel(channelName);
        LinkedList<EventHub> eventHubLinkedList = new LinkedList<>();
        for (MPeer mpeer : mPeers) {
            eventHubLinkedList.add(convertEventHub(mpeer));
        }
        return eventHubLinkedList;
    }

    private String getPeerLocation(MPeer mPeer) {
        return getLocation(mPeer) + mPeer.getPort();
    }

    private String getLocation(MPeer mPeer) {
        String grpc = "grpc://";
        if (mPeer.getTlsFlag()) {
            grpc = "grpcs://";
        }
        return grpc + mPeer.getHostAddress() + ":";
    }

    private String getEventHubLocation(MPeer mPeer) {
        return getLocation(mPeer) + mPeer.getEventPort();
    }

    public Set<Peer> getPeerByChannel(String channelName) throws InvalidArgumentException {
        List<MPeer> mPeers = peerRepository.selectPeerByChannel(channelName);
        Set<Peer> peerLinkedList = new HashSet<>();
        for (MPeer mPeer : mPeers) {
            peerLinkedList.add(convert(mPeer));
        }
        return peerLinkedList;
    }
}
